package com.gitee.fanx.rpc.server;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.gitee.fanx.rpc.JavaTypeResolver;
import com.gitee.fanx.rpc.RpcCodec;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author fanhang
 */
public class Route {
	private final Object bean;
	private final Method method;
	private final List<JavaType> paramTypes;
	private final String toString;

	public Route(Object bean, Method method) {
		this.bean = bean;
		this.method = method;
		this.paramTypes = JavaTypeResolver.methodParameters(method);
		toString = method.getName() + "#" + paramTypes.stream().map(x -> x.getRawClass().getSimpleName()).collect(Collectors.joining(","));
	}

	public Object handle(JsonNode body) throws InvocationTargetException, IllegalAccessException {
		if (this.paramTypes.isEmpty()) {
			return method.invoke(bean);
		}
		List<Object> args = this.parseParameters(body.elements());
		return method.invoke(bean, args.toArray());
	}

	private List<Object> parseParameters(Iterator<JsonNode> elements) {
		List<Object> args = new ArrayList<>();
		for (JavaType javaType : paramTypes) {
			if (elements.hasNext()) {
				JsonNode node = elements.next();
				args.add(RpcCodec.convert(node, javaType));
			} else {
				args.add(null);
			}
		}
		return args;
	}

	@Override
	public String toString() {
		return toString;
	}
}
